//! 路由表

use crate::conns::Conns;
use crate::conns::Fd;
use crate::history::History;
use crate::packet;
use alloc::collections::{BTreeMap, BTreeSet};
use unmp_id::Id;
use unmp_link::prelude::Connection;

/// 重要数据只能60秒发一次
const IMPORTANT_INTERVAL: u64 = 60_000;
/// 10秒未收到响应数据即判断超时
const TIMEOUT: u64 = 10_000;

struct Info {
    conns: BTreeSet<Fd>,
    send_time: u64,
    recv_time: u64,
    send_important: u64,
    recv_important: u64,
    history: History,
}
impl Info {
    fn new() -> Self {
        Self {
            conns: BTreeSet::new(),
            send_time: 0,
            recv_time: 0,
            send_important: 0,
            recv_important: 0,
            history: History::new(),
        }
    }
    fn can_send_important(&self, now: u64) -> bool {
        now > self.send_important + IMPORTANT_INTERVAL
    }
    fn can_recv_important(&self, now: u64) -> bool {
        now > self.recv_important + (IMPORTANT_INTERVAL * 9 / 10)
    }
    fn timeout(&self, now: u64) -> bool {
        now > self.send_time + TIMEOUT && self.recv_time < self.send_time || self.recv_time == 0
    }
}

/// 路由表
pub(crate) struct Router {
    id: Id,
    relay: bool,
    route: BTreeMap<Id, Info>,
    conns: Conns,
}
impl Router {
    pub fn new(id: Id, relay: bool) -> Self {
        Router {
            id,
            relay,
            route: BTreeMap::new(),
            conns: Conns::new(),
        }
    }
    /// 添加链路到路由表上
    pub fn add_conn(&mut self, conn: Connection) {
        self.conns.push(conn);
    }
}

impl Router {
    /// 接收数据包
    pub async fn recv(&mut self) -> packet::Packet {
        loop {
            let (fd, mut packet) = self.conns.recv().await;
            if packet.head.dst != self.id && !self.relay {
                continue;
            }
            let now = clock_source::now();
            // 历史记录，防止重复处理
            let info = self
                .route
                .entry(packet.head.src.clone())
                .or_insert(Info::new());
            info.conns.insert(fd);
            info.recv_time = now;
            if !info.history.insert(&packet) {
                continue;
            }
            log::trace!("recv {:?}", packet);
            // 处理数据
            if packet.head.dst == self.id {
                return packet;
            } else if self.relay && packet.head.ttl != 0 {
                packet.head.ttl -= 1;
                if packet.head.important && info.can_recv_important(now) {
                    info.recv_important = now;
                    let _ = self.conns.send(packet, |f| f != &fd).await;
                } else {
                    let info = self.route.get(&packet.head.dst);
                    if let Some(info) = info {
                        let fds = &info.conns;
                        let _ = self
                            .conns
                            .send(packet, |f| f != &fd && fds.contains(f))
                            .await;
                    }
                }
            }
        }
    }
    /// 发送数据包
    pub async fn send(&mut self, mut packet: packet::Packet) -> Result<(), ()> {
        log::trace!("send {:?}", packet);
        let info = self
            .route
            .entry(packet.head.dst.clone())
            .or_insert(Info::new());
        let now = clock_source::now();
        if info.recv_time >= info.send_time {
            info.send_time = now;
        }
        if (info.timeout(now) || info.conns.is_empty()) && info.can_send_important(now) {
            info.send_important = now;
            packet.head.important = true;
            self.conns.send(packet, |_| true).await
        } else {
            let fds = &info.conns;
            self.conns.send(packet, |f| fds.contains(f)).await
        }
    }
}
